/*
 * QTeXPreview
 * Copyright (C) 2008, Philip Pronin (philip.pronin@gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "aboutDialog.h"
#include "configDialog.h"
#include "tex.h"
#include "window.h"
#include "settings.h"

#include <QClipboard>
#include <QDomDocument>
#include <QFileDialog>
#include <QImageWriter>
#include <QMessageBox>
#include <QSettings>

MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) {
	setupUi(this);

	statusBar()->showMessage(tr("Ready"));
	labelRendering = new QLabel;
	labelRendering->setText(tr("Rendering..."));
	labelRendering->setVisible(false);
	statusBar()->addPermanentWidget(labelRendering);

	setCentralWidget(textEdit);

	loadSettings();
	setupLanguages();

	connect(QApplication::clipboard(), SIGNAL(dataChanged()), SLOT(clipboardDataChanged()));
	clipboardDataChanged();

	textEdit->setFocus();
}

MainWindow::~MainWindow() {
	saveSettings();
}

void MainWindow::loadSettings() {
	Settings* settings = Settings::getInstance();
	restoreGeometry(settings->getGeometry());
	restoreState(settings->getState());
	alwaysOnTop(settings->getStayOnTop());
}

void MainWindow::saveSettings() {
	Settings* settings = Settings::getInstance();
	settings->setGeometry(saveGeometry());
	settings->setState(saveState());
	Settings::freeInstance();
}

void MainWindow::setupLanguages() {
	QDomDocument doc("Lang");
	QFile file("lang/lang.xml");
	if (!file.open(QFile::ReadOnly)) return;
	if (!doc.setContent(&file)) {
		file.close();
		return;
	}
	file.close();

	QDomElement root = doc.documentElement();
	if (root.tagName() != "languages") return;

	QActionGroup* langGroup = new QActionGroup(this);
	langGroup->addAction(action_LangAuto);
	action_LangAuto->setChecked(true);

	QSignalMapper* signalMapper = new QSignalMapper(this);
	connect(signalMapper, SIGNAL(mapped(const QString&)), SLOT(language(const QString&)));
	signalMapper->setMapping(action_LangAuto, "");
	connect(action_LangAuto, SIGNAL(triggered()), signalMapper, SLOT(map()));

	langActions.push_back(qMakePair(QString(), action_LangAuto));

	QDomElement langEl = root.firstChildElement("lang");
	while (!langEl.isNull()) {
		QAction* langAction = new QAction(langEl.text(), this);
		langAction->setStatusTip(langEl.text());
		QString code = langEl.attribute("code");
		langAction->setCheckable(true);
		langGroup->addAction(langAction);
		langAction->setChecked(code == Settings::getInstance()->getLocale());
		menuLanguage->addAction(langAction);

		signalMapper->setMapping(langAction, code);
		connect(langAction, SIGNAL(triggered()), signalMapper, SLOT(map()));
		langEl = langEl.nextSiblingElement("lang");

		langActions.push_back(qMakePair(code, langAction));
	}
}

const QList<QPair<QString, QAction*> >& MainWindow::getLangActions() const {
	return langActions;
}

void MainWindow::language(const QString& code) {
	Settings* settings = Settings::getInstance();
	if (code == settings->getLocale()) return;
	settings->setLocale(code);
	QMessageBox::information(this, tr("Language"),
			tr("Please restart to apply changes"));
}

void MainWindow::clipboardDataChanged() {
	action_Paste->setEnabled(!QApplication::clipboard()->text().isEmpty());
}

void MainWindow::copy() {
	QApplication::clipboard()->setText(textEdit->text());
}

void MainWindow::textChanged() {
	renderWidget->setTeX(textEdit->text());
}

void MainWindow::renderStateChanged(RenderAreaWidget::RenderState state) {
	labelRendering->setVisible(state == RenderAreaWidget::Rendering);
	if (state == RenderAreaWidget::Waiting)
		action_Save->setEnabled(!renderWidget->getPixmap().isNull());
}

void MainWindow::save() {
	QImage image = renderWidget->getImage();
	if (image.isNull()) return;

	TeXFrontEnd* tex = TeXFrontEnd::create();

	QStringList filters;
	filters << "Windows Bitmap (*.bmp)";
	filters << "Joint Photographic Experts Group (*.jpg *.jpeg)";
	filters << "Portable Network Graphics (*.png)";
	filters << tex->getRenderFormatFilter();

	static QString* filter = new QString();
	QString fileName = QFileDialog::getSaveFileName(this, "", "", filters.join(";;"), filter);
	if (fileName.isEmpty()) return;

	QImageWriter writer(fileName);
	if (writer.supportsOption(QImageIOHandler::Description))
		writer.setText("Description", "QTeXPreview");

	if (!writer.write(image))
		if (fileName.endsWith("." + tex->getRenderFormat(), Qt::CaseInsensitive)) {
			QFile file(fileName);
			file.open(QFile::WriteOnly);
			file.write(tex->renderNow(textEdit->text()));
			file.close();
		}

	delete tex;

	statusBar()->showMessage(tr("File saved"));
}

void MainWindow::alwaysOnTop(bool enable) {
	Qt::WindowFlags flags = windowFlags();
	if (enable == (flags & Qt::WindowStaysOnTopHint) != 0) return;
	Settings::getInstance()->setStayOnTop(enable);

	if (enable) flags |= Qt::WindowStaysOnTopHint;
	else flags &= ~Qt::WindowStaysOnTopHint;

	setWindowFlags(flags);
	show();
}

void MainWindow::aboutDialog() {
	AboutDialog about(this);
	about.exec();
}

void MainWindow::configDialog() {
	ConfigDialog config(this);
	if (config.exec() == QDialog::Accepted) {
		Settings* settings = Settings::getInstance();

		action_AlwaysOnTop->setChecked(config.StayOnTop());
		alwaysOnTop(config.StayOnTop());

		QPair<QString, QAction*>& p = langActions[config.LanguageCode()];
		p.second->setChecked(true);
		language(p.first);

		settings->setSyntaxHighlighting(config.Highlight());
		settings->setBracketsMatching(config.BracketsMatching());
		textEdit->applySettings();
	}
}

void MainWindow::toolBoxCommand(QObject* cmd) {
	ToolButtonInfo* info = (ToolButtonInfo*)cmd;
	QTextCursor cursor = textEdit->textCursor();
	cursor.insertText(info->cmd.tex);
	cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor,
		info->cmd.tex.size() - info->cmd.cursor);
	textEdit->setTextCursor(cursor);
}
